package org.oep;

import java.io.IOException;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Calendar;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Font;

public class Mingler extends Canvas {
	private Vector messageLog = new Vector();
	
	private int currentEntry = 0;
	private int currentDevice = 0;
	
	private JMingle parent;
	private NumberWidget scanInterval;
	
	private Image antennaIcon;
	private Image persistentIcon;
	private Image logBuffer;
	private MingleNode deviceBuffer;
	
	Font normal;
	Font small = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL);
	
	// Height of font.
	private final int lineHeight = small.getHeight();
	// Initial position on screen (each message moves up by px)
	private final int initialPosition = (2 * lineHeight);
	private final int stopPoint = (int)( this.getHeight() * 0.85 );
	
	Mingler(JMingle parent) {
		this.parent = parent;
		drawLogBuffer();
		
		try {
			antennaIcon = Image.createImage("/res/icons/antenna.png");
		} catch (IOException e) {
			antennaIcon = null;
		}
		try {
			persistentIcon = Image.createImage("/res/icons/people.png");
		} catch (IOException e) {
			persistentIcon = null;
		}
	}
	
	/*
	 * Inherited from Canvas
	 */
	//--------------------------------------------------------------//
	public void keyPressed(int keyCode) {
		int gameCode = this.getGameAction(keyCode);
		switch(gameCode) {
		case Canvas.UP: this.scrollLogUp(); this.repaint(); break;
		
		case Canvas.DOWN: this.scrollLogDown(); this.repaint(); break;
		
		case Canvas.RIGHT:
			if(scanInterval.isActive()) {
				scanInterval.increment();
			}
			else {
				this.scrollDeviceRight();
			}
			this.repaint();
			break;
			
		case Canvas.LEFT:
			if(scanInterval.isActive()) {
				scanInterval.decrement();
			}
			else {
				this.scrollDeviceLeft();
			}
			this.repaint();
			break;
			
		case Canvas.FIRE:
			if(scanInterval.isActive()) {
				parent.setOpt("persistent_scan_interval", String.valueOf(scanInterval.getValue())); 
				parent.processCode(JMingle.DO_PERSISTENT_SCAN);
				scanInterval.setActive(false);
			}
			this.repaint();
			break;
		default:
			scanInterval.setActive(false);
			break;
		}
	}
	
	public void keyRepeated(int keyCode) {
		keyPressed(keyCode);
	}
	
	protected void paint(Graphics g) {
		if(normal == null) normal = g.getFont();
		if(scanInterval == null)
			scanInterval = new NumberWidget(this, "Scan interval:", "m", 60, 1, 5);
		
		g.setColor(255, 255, 255);
		g.fillRect(0, 0, this.getWidth(), this.getHeight());
		g.setColor(0);
		g.setFont(small);
			
		// Top-left: Draw the memory usage
		Runtime rt = Runtime.getRuntime();
		int pct = new Float(100 * (rt.totalMemory() - rt.freeMemory()) / (rt.totalMemory())).intValue();
		
		g.drawString("P: " + pct + "% T: " + rt.totalMemory() / 1000 + 'K', 0, 0, Graphics.TOP|Graphics.LEFT);
		
		// Top-right: Draw the busy icon and scan icon
		if(antennaIcon == null || persistentIcon == null) {
			String mode = new String();
			if(parent.persistentScanActive()) mode += "[p]";
			if(parent.antennaIsBusy()) mode += "[a]";
			if(mode.length() > 0)
				g.drawString(mode, this.getWidth(), 0, Graphics.TOP | Graphics.RIGHT);
		}
		
		else {
			if(parent.antennaIsBusy()) {
				g.drawImage(antennaIcon, this.getWidth(), 0, Graphics.TOP | Graphics.RIGHT);
			}
			if(parent.persistentScanActive()) {
				g.drawImage(persistentIcon, this.getWidth() - antennaIcon.getWidth(), 0, Graphics.TOP | Graphics.RIGHT);
			}
		}
		
		
		// Message log
		if(logBuffer == null)
			drawLogBuffer();
		
		g.drawImage(logBuffer, 0, initialPosition, Graphics.LEFT | Graphics.TOP);

		
		// Bottom: Device browse
		if(deviceBuffer == null)
			updateCurrentDevice();
		
		if(deviceBuffer != null) {
			// Device browser
			String out = new String();
			if(currentDevice > 0) out += "< ";
			out += deviceBuffer.getName();
			if(currentDevice < parent.numberOfDevices() - 1) out += " >";
			
			g.drawString(out, this.getWidth() / 2, this.getHeight() - small.getHeight(), Graphics.HCENTER | Graphics.BOTTOM);
			
			
			// Position
			String pos = new String();
			pos += (currentDevice + 1);
			
			String countLine = pos + "/" + parent.numberOfDevices(); 
			g.setFont(small);
			g.drawString(countLine, this.getWidth() / 2, this.getHeight(), Graphics.HCENTER | Graphics.BOTTOM);
		}
		

		
		
		// Widgets
		scanInterval.paint(g);
		
	}
	
	/*
	 * Internal functions
	 */
	//--------------------------------------------------------------//
	
	public void scrollLogUp() {
		if(currentEntry > 0) {
			currentEntry--;
			drawLogBuffer();
		}
	}
	public void scrollLogDown() {
		if(hasOverflow() && currentEntry < messageLog.size() - 1) {
			currentEntry++;
			drawLogBuffer();
		}
	}
	public void scrollDeviceLeft() {
		if(currentDevice > 0) {
			currentDevice--;
			updateCurrentDevice();
		}
	}
	public void scrollDeviceRight() {
		if(currentDevice < parent.numberOfDevices() - 1) {
			currentDevice++;
			updateCurrentDevice();
		}
	}
	
	private void updateCurrentDevice() {
		System.out.println("Update device");
		if(parent.numberOfDevices() > 0) {
			Enumeration nodes = parent.getDevices();
			MingleNode n = null;
			
			for(int i = 0; i < parent.numberOfDevices(); i++) {
				n = (MingleNode) nodes.nextElement();
				if(i == currentDevice) {
					break;
				}
			}
			deviceBuffer = n;
		} else
			deviceBuffer = null;
	}

	private void drawLogBuffer() {
		System.out.println("Draw Log Buffer");
		Graphics g;
		if(logBuffer == null) {
			logBuffer = Image.createImage(this.getWidth(), stopPoint - initialPosition);
			g = logBuffer.getGraphics();
		}
		else {
			g = logBuffer.getGraphics();
			g.setColor(0xFFFFFF);
			g.fillRect(0, 0, logBuffer.getWidth(), logBuffer.getHeight());
		}
		g.setColor(0);
		g.setFont(small);
		
		if(messageLog.size() > 0) {
			// Height of font.
			int px = g.getFont().getHeight();
			// Initial position on screen (each message moves up by px)
			int pos = 0;
			
			// Fix it just in case
			if(currentEntry >= messageLog.size()) currentEntry = messageLog.size() - 1;
			if(currentEntry < 0) currentEntry = 0;
			
			for(int i = currentEntry; i < messageLog.size(); i++) {
				// Calculate y-position of this entry.
				pos += px;
				
				// Prevent messages from going within two lines of the top
				if( pos > logBuffer.getHeight() ) break;

				String [] tokens = Utils.tokenize( (String) messageLog.elementAt(i) );

				String line = new String();
				for(int j = 0; j < tokens.length; j++) {
					// Check for overflow in this for loop
					if(pos > logBuffer.getHeight()) break;
					
					char [] chars = (line + tokens[j]).toCharArray();
					int width = g.getFont().charsWidth(chars, 0, chars.length);
					if(width > this.getWidth()) {
						g.drawString(line, 0, pos, Graphics.LEFT | Graphics.BOTTOM);
						pos += px;
						line = tokens[j];
					} else {
						line += tokens[j];
					}
					if(j != tokens.length - 1) line += " ";
				}
				if(line.length() > 0 && pos < logBuffer.getHeight()) {
					g.drawString(line, 0, pos, Graphics.LEFT | Graphics.BOTTOM);
				}
			}
		}
	}
	
	
	/*
	 * External functions
	 */
	//--------------------------------------------------------------//
	public void showMessage(String message) {
		String hour, minute;
		Calendar calendar = Calendar.getInstance();
		int m = calendar.get(Calendar.MINUTE);
		int h = calendar.get(Calendar.HOUR_OF_DAY);
		boolean hadOverflow = this.hasOverflow();
		
		if(m < 10) minute = "0" + m;
		else minute = String.valueOf(m);
		
		if(h < 10) hour = "0" + h;
		else hour = String.valueOf(h);
		
		messageLog.addElement(hour + ":" + minute + ": " + message);
		
		if(!hadOverflow) {
			while(this.hasOverflow())
				this.scrollLogDown();
		}
		
		drawLogBuffer();
		this.repaint();
	}
	
	public boolean hasOverflow() {
		int pos = 0;
		for(int i = currentEntry; i < messageLog.size(); i++) {
			// Calculate y-position of this entry.
			pos += lineHeight;
			
			// Prevent messages from going within two lines of the top
			if( pos > logBuffer.getHeight() ) return true;

			String [] tokens = Utils.tokenize( (String) messageLog.elementAt(i) );

			String line = new String();
			for(int j = 0; j < tokens.length; j++) {
				// Check for overflow in this for loop
				if(pos > logBuffer.getHeight()) return true;
				
				char [] chars = (line + tokens[j]).toCharArray();
				int width = small.charsWidth(chars, 0, chars.length);
				if(width > this.getWidth()) {
					pos += lineHeight;
					line = tokens[j];
				} else {
					line += tokens[j];
				}
				if(j != tokens.length - 1) line += " ";
			}
			
		}
		if(pos < logBuffer.getHeight())
			return false;
		else
			return true;
	}
	
	public void showIntervalScreen() {
		scanInterval.setActive(true);
		this.repaint();
	}
	
	public void hideIntervalScreen() {
		scanInterval.setActive(false);
		this.repaint();
	}
	
	public void clearMessageLog() {
		messageLog.removeAllElements();
		currentEntry = 0;
		this.repaint();
	}	
}
